#ifndef _SQL_STORAGE_H
#define _SQL_STORAGE_H

class Mutex;

template<typename T>
class DLL_EXPORT SQLStorage
{
	stdext::hash_map<ui32, T*> records;
	Mutex m_readlock;
public:
	void Clear()
	{
		records.clear();
	}

	bool Load(const char* table, const char* format, Database* db)
	{
		QResult* res = db->SafeQuery("Select * from %s", table);
		if(!res)
		{
			Log->Error("SQLStorage", "Load failed for table '%s'", table);
			return false;
		}
		if(res->NumFields() != strlen(format))
		{
			Log->Error("SQLStorage", "Incorrect format of table '%s'", table);
			return false;
		}
		if(strlen(format) * 4 != sizeof(T))
		{
			Log->Error("SQLStorage", "Possible invalid matches in table '%s' and struct '%s'", table, typeid(T).name());
		}
		ui32 nr = res->NumRows();
		if(!nr)
		{
			Log->Notice("SQLStorage", "Loaded %u rows from table '%s'", nr, table);
			return true;
		}
		do
		{
			T* tmp = new T();
			ui8* cpos = (ui8*)tmp;
			QField* rw = res->Fetch();
			for(register ui32 i = 0; i < strlen(format); ++i)
			{
				switch(*(format + i))
				{
				case 'u':
					{
						*(ui32*)cpos = rw[i];
						cpos += 4;
						break;
					}
				case 'f':
					{
						*(float*)cpos = rw[i];
						cpos += 4;
						break;
					}
				case 's':
					{
						*(char**)cpos = new char[strlen(rw[i]) + 1];
						strcpy(*(char**)cpos, rw[i]);
						cpos += 4;
						break;
					}
				}
			}
			records[*(ui32*)tmp] = tmp;

		}
		while(res->NextRow());
		Log->Notice("SQLStorage", "Loaded %u rows from table '%s'", nr, table);
		delete res;
		return true;
	}

	T* LookupEntry(ui32 id)
	{
		return records[id];
	}
	ui32 GetMaxElement()
	{
		return max_element(records.begin(), records.end())->first;
	}

	typename typedef stdext::hash_map<ui32, T*>::iterator StorageIterator;
	
	StorageIterator Begin()
	{
		return records.begin();
	}

	StorageIterator End()
	{
		return records.end();
	}

	void AcquireReadLock() { m_readlock.Acquire(); }
	void ReleaseReadLock() { m_readlock.Release(); }

	void AddEntry(T* instance) { records[*(ui32*)instance] = instance; }
};


#endif